package org.bulu.project.system.util;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.internal.Mimetypes;
import com.aliyun.oss.model.*;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.bulu.project.common.result.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
/*
    Oss工具类
 */
@Slf4j
@Component
public class OssUtil {
    private String OSS_BUCKET = "msp-1";
    private String OSS_BUCKET_URL = "https://msp-1.oss-cn-beijing.aliyuncs.com/";

    @Value("${directory.chunk}")
    private String CHUNK_DIRECTORY;   // 分片存储目录
    private static String BUCKET_NAME = "msp-1";
    private static String EDPOINT = "http://oss-cn-beijing.aliyuncs.com";
    private static String ACCESS_KEY_ID = "LTAI5t9o9mGCkRNYpcE7rKCU" ;
    private static String ACCESS_KEY_SECRET = "3qrXj6qawOeLd2ax7sVcklZIZRXtVq";


    /**
     * 往阿里云对象存储上传单张图片
     * @param file 图片文件
     * @param type 图片分类，如 cover、carousel、other等，不允许空字符串，这里没有做判断了，自己注意就好
     * @return  图片的URL地址
     * @throws IOException
     */
    public String uploadImage(@NonNull MultipartFile file, @NonNull String type) throws IOException {
        CredentialsProvider credentialsProvider;
        // 生成文件名
        String originalFilename = file.getOriginalFilename();   // 获取原文件名
        String ext = "." + FilenameUtils.getExtension(originalFilename);    // 获取文件后缀
        String uuid = System.currentTimeMillis() + UUID.randomUUID().toString().replace("-", "");
        String fileName = uuid + ext;
        // 完整路径名
        String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date()).replace("-", "");
        String filePathName = date + "/img/" + type + "/" + fileName;
        try {
            credentialsProvider = new DefaultCredentialProvider(ACCESS_KEY_ID, ACCESS_KEY_SECRET);
            OSS ossClient = new OSSClientBuilder().build(EDPOINT, credentialsProvider);
            ossClient.putObject(
                    OSS_BUCKET, // 仓库名
                    filePathName,   // 文件名（含路径）
                    file.getInputStream()   // 数据流
            );
        } catch (OSSException oe) {
            log.error("OSS出错了:" + oe.getErrorMessage());
            throw oe;
        } catch (ClientException ce) {
            log.error("OSS连接出错了:" + ce.getMessage());
            throw ce;
        }
        return OSS_BUCKET_URL + filePathName;
    }


    public String UploadVideo(MultipartFile file) {
        // 计算文件的MD5值
        String md5 = getFileMD5(file);
        // 检查MD5值对应的文件是否已存在
        boolean exists = checkFileExistsByMD5(md5);
        if (exists) {
            // 如果存在，则直接返回文件的URL
            log.info("文件已存在，MD5值：{}", md5);
            String existingUrl = OSS_BUCKET_URL + "/md5-folder/" + md5 + ".mp4"; // 假设所有基于MD5的文件都放在/md5-folder/下
            return existingUrl;
        } else {
            // 如果不存在，则进行分片上传
            // 修改objectName为MD5值
            String objectName = "md5-folder/" + md5 + ".mp4";
            // 分片上传后，返回新上传文件的URL
            return Upload(file, objectName);
        }
    }

    // 计算文件的MD5值
    private String getFileMD5(MultipartFile file) {
        try {
            InputStream inputStream = file.getInputStream();
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] buffer = new byte[1024];
            int read;
            while ((read = inputStream.read(buffer)) != -1) {
                md.update(buffer, 0, read);
            }

            byte[] digest = md.digest();
            StringBuilder hexString = new StringBuilder();
            for (byte b : digest) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) hexString.append('0');
                hexString.append(hex);
            }

            return hexString.toString();
        } catch (NoSuchAlgorithmException | IOException e) {
            throw new RuntimeException(e);
        }
    }

    // 检查OSS中基于MD5值的文件是否存在
    private boolean checkFileExistsByMD5(String md5) {
        OSS ossClient = null;
        CredentialsProvider credentialsProvider;
        try {
            credentialsProvider = new DefaultCredentialProvider(ACCESS_KEY_ID, ACCESS_KEY_SECRET);
            ossClient = new OSSClientBuilder().build(EDPOINT, credentialsProvider);
            // 判断文件是否存在
            boolean found = ossClient.doesObjectExist(BUCKET_NAME, "md5-folder/" + md5 + ".mp4");
            return found;
        } catch (OSSException | ClientException e) {
            throw new RuntimeException(e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    // 分片上传
    public String Upload(MultipartFile file, String objectName) {
        CredentialsProvider credentialsProvider = new DefaultCredentialProvider(ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        OSS ossClient = null;
        try {
            ossClient = new OSSClientBuilder().build(EDPOINT, credentialsProvider);

            // 创建InitiateMultipartUploadRequest对象。
            InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(BUCKET_NAME, objectName);
            InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
            String uploadId = upresult.getUploadId();

            // partETags是PartETag的集合。
            List<PartETag> partETags = new ArrayList<>();

            // 每个分片的大小，单位为字节。
            final long partSize = 1 * 1024 * 1024L; // 1 MB

            // 读取文件内容，并分片上传
            InputStream inputStream = file.getInputStream();
            byte[] buffer = new byte[(int) partSize];
            int bytesRead;
            int partNumber = 1;

            while ((bytesRead = inputStream.read(buffer)) != -1) {
                byte[] data = new byte[bytesRead];
                System.arraycopy(buffer, 0, data, 0, bytesRead);

                // 创建UploadPartRequest对象
                UploadPartRequest uploadPartRequest = new UploadPartRequest();
                uploadPartRequest.setBucketName(BUCKET_NAME);
                uploadPartRequest.setKey(objectName);
                uploadPartRequest.setUploadId(uploadId);
                uploadPartRequest.setInputStream(new ByteArrayInputStream(data));
                uploadPartRequest.setPartSize(data.length);
                uploadPartRequest.setPartNumber(partNumber++);

                // 上传分片
                UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
                partETags.add(uploadPartResult.getPartETag());
            }

            // 完成分片上传
            CompleteMultipartUploadRequest completeMultipartUploadRequest =
                    new CompleteMultipartUploadRequest(BUCKET_NAME, objectName, uploadId, partETags);
            CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);

            System.out.println(completeMultipartUploadResult.getETag());
            return OSS_BUCKET_URL + objectName;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return null;
    }
    //根据文件地址分片上传一个文件
//    public String UploadVideo(String videoUrl){
//        // 计算文件的MD5值
//        String md5 = getFileMD5(videoUrl);
//        // 检查MD5值对应的文件是否已存在
//        boolean exists = checkFileExistsByMD5(md5);
//        if (exists) {
//            // 如果存在，则直接返回文件的URL
//            log.info("文件已存在，MD5值：{}", md5);
//            String existingUrl = OSS_BUCKET_URL + "/md5-folder/" + md5 + ".mp4"; // 假设所有基于MD5的文件都放在/md5-folder/下
//            return existingUrl;
//        } else {
//            // 如果不存在，则进行分片上传
//            // 修改objectName为MD5值
//            String objectName = "md5-folder/" + md5 + ".mp4";
//            // 分片上传后，返回新上传文件的URL
//            return Upload(videoUrl, objectName);
//        }
//    }
//    // 计算文件的MD5值
//    private String getFileMD5(String filePath) {
//        try {
//            InputStream fis = new FileInputStream(filePath);
//            MessageDigest md = MessageDigest.getInstance("MD5");
//            byte[] buffer = new byte[1024];
//            int read;
//            while ((read = fis.read(buffer)) != -1) {
//                md.update(buffer, 0, read);
//            }
//
//            byte[] digest = md.digest();
//            StringBuilder hexString = new StringBuilder();
//            for (byte b : digest) {
//                String hex = Integer.toHexString(0xff & b);
//                if (hex.length() == 1) hexString.append('0');
//                hexString.append(hex);
//            }
//
//            return hexString.toString();
//        } catch (NoSuchAlgorithmException | IOException e) {
//            throw new RuntimeException(e);
//        }
//    }
//    // 检查OSS中基于MD5值的文件是否存在（这里需要根据实际情况实现）
//    private boolean checkFileExistsByMD5(String md5) {
//        CredentialsProvider credentialsProvider ;
//        try {
//            credentialsProvider = new DefaultCredentialProvider(ACCESS_KEY_ID, ACCESS_KEY_SECRET);
//            ossClient = new OSSClientBuilder().build(EDPOINT, credentialsProvider);
//            // 判断文件是否存在。如果返回值为true，则文件存在，否则存储空间或者文件不存在。
//            // 设置是否进行重定向或者镜像回源。默认值为true，表示忽略302重定向和镜像回源；如果设置isINoss为false，则进行302重定向或者镜像回源。
//            //boolean isINoss = true;
//            boolean found = ossClient.doesObjectExist(BUCKET_NAME,  "md5-folder/" + md5 + ".mp4");
//            //boolean found = ossClient.doesObjectExist(bucketName, objectName, isINoss);
//            return found;
//        } catch (OSSException oe) {
//            System.out.println("Caught an OSSException, which means your request made it to OSS, "
//                    + "but was rejected with an error response for some reason.");
//            System.out.println("Error Message:" + oe.getErrorMessage());
//            System.out.println("Error Code:" + oe.getErrorCode());
//            System.out.println("Request ID:" + oe.getRequestId());
//            System.out.println("Host ID:" + oe.getHostId());
//        } catch (ClientException ce) {
//            System.out.println("Caught an ClientException, which means the client encountered "
//                    + "a serious internal problem while trying to communicate with OSS, "
//                    + "such as not being able to access the network.");
//            System.out.println("Error Message:" + ce.getMessage());
//        } finally {
//            if (ossClient != null) {
//                ossClient.shutdown();
//            }
//        }
//        // 伪代码，具体实现取决于你的OSS客户端库和API
//        // 你可能需要列出特定前缀的文件，然后逐个检查它们的MD5值或文件名
//        // 或者，如果OSS支持通过MD5直接查找文件，则可以使用该功能
//        return false; // 假设不存在
//    }
//    //分片上传
//    public String Upload(String videoUrl,String objectName) {
//        CredentialsProvider credentialsProvider ;
//        // 创建OSSClient实例。
//        try {
//            credentialsProvider = new DefaultCredentialProvider(ACCESS_KEY_ID, ACCESS_KEY_SECRET);
//            ossClient = new OSSClientBuilder().build(EDPOINT, credentialsProvider);
//            // 创建InitiateMultipartUploadRequest对象。
//            InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(BUCKET_NAME, objectName);
//            // 如果需要在初始化分片时设置请求头，请参考以下示例代码。
//            ObjectMetadata metadata = new ObjectMetadata();
//            if (metadata.getContentType() == null) {
//                metadata.setContentType(Mimetypes.getInstance().getMimetype(new File(videoUrl), objectName));
//            }
//            // 初始化分片。
//            InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
//            // 返回uploadId。
//            String uploadId = upresult.getUploadId();
//            // partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
//            List<PartETag> partETags =  new ArrayList<PartETag>();
//            // 每个分片的大小，用于计算文件有多少个分片。单位为字节。
//            final long partSize = 1 * 1024 * 1024L;   //1 MB。
//            // 根据上传的数据大小计算分片数。以本地文件为例，说明如何通过File.length()获取上传数据的大小。
//            final File sampleFile = new File(videoUrl);
//            long fileLength = sampleFile.length();
//            int partCount = (int) (fileLength / partSize);
//            if (fileLength % partSize != 0) {
//                partCount++;
//            }
//            // 遍历分片上传。
//            for (int i = 0; i < partCount; i++) {
//                long startPos = i * partSize;
//                long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
//                UploadPartRequest uploadPartRequest = new UploadPartRequest();
//                uploadPartRequest.setBucketName(BUCKET_NAME);
//                uploadPartRequest.setKey(objectName);
//                uploadPartRequest.setUploadId(uploadId);
//                // 设置上传的分片流。
//                // 以本地文件为例说明如何创建FIleInputstream，并通过InputStream.skip()方法跳过指定数据。
//                InputStream instream = new FileInputStream(sampleFile);
//                instream.skip(startPos);
//                uploadPartRequest.setInputStream(instream);
//                // 设置分片大小。除了最后一个分片没有大小限制，其他的分片最小为100 KB。
//                uploadPartRequest.setPartSize(curPartSize);
//                // 设置分片号。每一个上传的分片都有一个分片号，取值范围是1~10000，如果超出此范围，OSS将返回InvalidArgument错误码。
//                uploadPartRequest.setPartNumber( i + 1);
//                // 每个分片不需要按顺序上传，甚至可以在不同客户端上传，OSS会按照分片号排序组成完整的文件。
//                UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
//                // 每次上传分片之后，OSS的返回结果包含PartETag。PartETag将被保存在partETags中。
//                partETags.add(uploadPartResult.getPartETag());
//            }
//
//
//            // 创建CompleteMultipartUploadRequest对象。
//            // 在执行完成分片上传操作时，需要提供所有有效的partETags。OSS收到提交的partETags后，会逐一验证每个分片的有效性。当所有的数据分片验证通过后，OSS将把这些分片组合成一个完整的文件。
//            CompleteMultipartUploadRequest completeMultipartUploadRequest =
//                    new CompleteMultipartUploadRequest(BUCKET_NAME, objectName, uploadId, partETags);
//            // 完成分片上传。
//            CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
//            System.out.println(completeMultipartUploadResult.getETag());
//            return OSS_BUCKET_URL+objectName;
//        } catch (OSSException oe) {
//            System.out.println("Caught an OSSException, which means your request made it to OSS, "
//                    + "but was rejected with an error response for some reason.");
//            System.out.println("Error Message:" + oe.getErrorMessage());
//            System.out.println("Error Code:" + oe.getErrorCode());
//            System.out.println("Request ID:" + oe.getRequestId());
//            System.out.println("Host ID:" + oe.getHostId());
//        } catch (FileNotFoundException e) {
//            throw new RuntimeException(e);
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        } finally {
//            if (ossClient != null) {
//                ossClient.shutdown();
//            }
//        }
//        return null;
//    }
    /*
       删除文件
    */
    public boolean deleteFile(String objectName) {
        CredentialsProvider credentialsProvider = new DefaultCredentialProvider(ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(EDPOINT, credentialsProvider);

        try {
            // 假设https://msp-1.oss-cn-beijing.aliyuncs.com/是固定的前缀
            String prefix = "https://msp-1.oss-cn-beijing.aliyuncs.com/";
            // 检查URL是否以该前缀开始
            if (objectName.startsWith(prefix)) {
                // 提取并打印路径部分
                String path = objectName.substring(prefix.length());
                // 删除文件或目录。如果要删除目录，目录必须为空。
                ossClient.deleteObject(BUCKET_NAME, path);
                return true;
            } else {
                return false;
            }
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return false;
    }
}
